package src.model.gameObject.ability;

import src.model.gameObject.PlayerGameObject;
import src.model.gameWorld.PlayerLookupTable;
import src.model.gameWorld.Position;
/**
 * @author Tristan
 * <b>Overview</b><br>
 * <p> This represents the triggerable, or "activatable" abilities that player owned game objects have. These
 * are basically the types of actions that the user of the program can explicitly tell a player owned game
 * object to do. The two methods of noe here are queueToMission and execute. queueToMission is invoked by the
 * GameObjectEventManager when it recieves a "use ability" request (key pressed). This tells the Ability to queue itself
 * it's PlayerGameObject's Mission queue. execute is called by the PlayerGameObject when it is to actually be executed.</p>
 * <br><br>
 * <b>Responsibilites</b><br>
 * <ul>
 * <li>Provide an interface through which to talk to ActiveAbilities.</li>
 * <li>Keep track of how many times an ability can be performed.</li>
 * </ul>
 * <br><br>
 * <b>Collaborators</b><br>
 * same as superclass<br>
 * <b>Implementor:</b> Tristan Lohman<br>
 * <b>Tester</b> - Bruce<br>

 *
 */
public abstract class ActiveAbility extends Ability {

	private float currentActionPoints;
	/**
	 * This creates an ActiveAbility
	 * @param pgo The PlayerGameObject owning the 
	 * @param aType
	 * @param playerLookup The PlayerLookupTable for this.
	 */
	public ActiveAbility(PlayerGameObject pgo, AbilityType aType, PlayerLookupTable playerLookup) {
		super(pgo, aType, playerLookup);
	}
	
	/**
	 * This overrides the inherited method gameObject(), to return the PlayerGameObject of the
	 ActiveAbility. PlayerGameObject is a subtype of GameObject, so this will still work
	 even when a GameObject is expected.
	 * @return The PlayerGameObject associated with this ActiveAbility.
	 */
	public PlayerGameObject gameObject(){ return (PlayerGameObject)super.gameObject(); }

	/**
	 * The number of actionPoints currently remaining. ActionPoints are necessesary to allow ActiveAbilities
	 * to perform their function. If there aren't enough, the actioncan not be performed (Movement points, number of
	 * attacks, etc.). 
	 * @return Number of action points remaining.
	 */
	public float currentActionPoints(){	return currentActionPoints;	}
	
	/**
	 * Used to modify the number of action points remaining. This is also how they are refreshed when needed.
	 * @param modify The amount to modify the action points by. Positive = give more. Negative = take away.
	 */
	public void modifyActionPoints(int modify){
		currentActionPoints += modify;
		if (currentActionPoints < 0) currentActionPoints = 0;
		if (currentActionPoints > maxActionPoints()) currentActionPoints = maxActionPoints();
	}
	
	/**
	 * Gives the maximum number of action points for this ability.
	 * @return Maximum number of action points that this ability can use.
	 */
	public float maxActionPoints()	{	return super.getAttribute(AbilityAttributes.MAXIMUM);}
	
	protected PlayerLookupTable playerLookupTable(){ return (PlayerLookupTable)super.lookupTable();}
	
	/**
	 * Tells the ability to do its thing.
	 * 
	 * @param position The positions that the ActiveAbility MAY need.
	 * @return The result, success, failed, or impossible, of the action. 
	 */
	public abstract AbilityReturnResult execute(Position... position);
	
	/**
	 * This is in charge of queueing an ActiveAbility into a PlayerGameObject's mission queue. This
	 * first checks to see if enough positions have been passed into it. If not, it returns false to
	 * notify the GameObjectEventHandler that it needs to have the user select a tile. If so, it then
	 * tells the PlayerGameObject to add this to the mission queue with these Position parameters.
	 * @param position The positions that have been selected to be passed to this ActiveAbility (can be zero).
	 * @return True = Enough positions. False = Not enough positions.
	 */
	public abstract boolean queueToMission(Position...position);
	
	/**
	 * Use one action point
	 * @return Whether or not this was successful (false indicates not enough action points)
	 */
	public boolean useActionPoint(){
		return useActionPoint(1);
	}
	
	/**
	 * Use a number of action points.
	 * @param numActionPoints The number of action points to use.
	 * @return True if successful, False if not (indicates not enough action points).
	 */
	public boolean useActionPoint(int numActionPoints){
		if (!hasActionPoints(numActionPoints)) return false;
		currentActionPoints -= numActionPoints;
		return true;
	}
	
	/**
	 * Asks to see if this ActiveAbility has enough action points to satisfy using these action points
	 * @param numActionPoints The number of action points testing.
	 * @return True if it has enough, false if not.
	 */
	public boolean hasActionPoints(int numActionPoints){
		if (numActionPoints > currentActionPoints) return false;
		return true;
	}
	
	/**
	 * Performs the all events necessary on a new turn. 
	 *
	 */
	public void newTurn(){
		this.currentActionPoints = maxActionPoints();
	}
}
